package state

import (
	"luu/number"
	"math"
)

var (
	iadd = func(a, b int64) int64 { return a + b }
	fadd = func(a, b float64) float64 { return a + b }
	isub = func(a, b int64) int64 { return a - b }
	fsub = func(a, b float64) float64 { return a - b }
	imul = func(a, b int64) int64 { return a * b }
	fmul = func(a, b float64) float64 { return a / b }
	imod = number.IMod
	fmod = number.FMod

	pow = math.Pow
	div = func(a, b float64) float64 { return a / b }

	iidiv = number.IFloorDiv
	fidiv = number.FFloorDiv

	band = func(a, b int64) int64 { return a & b }
	bor  = func(a, b int64) int64 { return a | b }
	bxor = func(a, b int64) int64 { return a ^ b }

	shl = number.ShiftLeft
	shr = number.ShiftRight

	//一元运算符
	iunm = func(a, _ int64) int64 { return -a }
	funm = func(a, _ float64) float64 { return -a }
	bnot = func(a, _ int64) int64 { return ^a }
)

type operator struct {
	integerFunc func(int64, int64) int64
	floatFunc   func(float64, float64) float64
}

var operators = []operator{
	{iadd, fadd},
	{isub, fsub},
	{imul, fmul},
	{imod, fmod},
	{nil, pow},
	{nil, div},
	{iidiv, fidiv},
	{band, nil},
	{bor, nil},
	{bxor, nil},
	{shl, nil},
	{shr, nil},
	{iunm, funm},
	{bnot, nil},
}

func (this *luaState) Arith(op ArithOp) {
	var c, b luaValue
	b = this.stack.pop()
	if op != LUA_OPUNM && op != LUA_OPBNOT {
		c = this.stack.pop()
	} else {
		c = b
	}
	modRes := this._arith(op, c, b)
	this.stack.push(modRes)
}

func (this *luaState) _arith(op ArithOp, a, b luaValue) luaValue {
	optr := operators[op]
	if optr.floatFunc == nil { // bitwise 计算，字符串也可以参与，浮点数也可以
		if x, ok1 := Obj2Integer(a); ok1 {
			if y, ok2 := Obj2Integer(b); ok2 {
				return optr.integerFunc(x, y)
			}
		}
	} else {
		//如果两个操作数实际都是 int 类型，那么按照 intFunc 计算
		//如果其中有个是 string 或者float ，那就按float 的算
		if x, ok1 := a.(int64); ok1 {
			if y, ok2 := b.(int64); ok2 {
				return optr.integerFunc(x, y)
			}
		}
		if x, ok1 := Obj2Float(a); ok1 {
			if y, ok2 := Obj2Float(b); ok2 {
				return optr.floatFunc(x, y)
			}
		}
	}
	return nil
}
